<?php

namespace App\Services;

/**
 * 支付宝相关服务
 * @package App\Services
 */
class AliPayService {

    /**
     * 支付宝对象
     * @var \AopClient
     */
    private $aop;

    /**
     * 支付宝配置信息
     * @var \Phalcon\Config
     */
    private $config;

    function __construct($config) {
        include(APP_PATH . '/app/libraries/alipay/AopSdk.php');
        $this->config = $config;
    }

    #region 初始化

    /**
     * 初始化
     */
    private function _init() {
        $this->aop = new \AopClient();
        $this->aop->gatewayUrl = $this->config->gatewayUrl;
        $this->aop->appId = $this->config->appId;
        $this->aop->rsaPrivateKey = $this->config->rsaPrivateKey; //请填写开发者私钥去头去尾去回车，一行字符串
        $this->aop->alipayrsaPublicKey = $this->config->alipayrsaPublicKey; //请填写支付宝公钥，一行字符串
        $this->aop->apiVersion = '1.0';
        $this->aop->signType = 'RSA2';
        $this->aop->postCharset = 'utf-8';
        $this->aop->format = 'json';
    }

    #endregion

    #region 单笔转账到支付宝账户相关

    #region 单笔转账到支付宝账户接口（alipay.fund.trans.toaccount.transfer）

    /**
     * 单笔转账到支付宝账户接口
     * @param $payeeAccount 收款方账户 支付宝唯一用户号
     * @param $outBizNo 商户转账唯一订单号 即本平台唯一订单号
     * @param $amount 转账金额
     * @param string $remark 转账备注 企业账户转账$amount>=50000元时不能为空（少于200个英文/100个汉字）
     * @return array 支付成功时['code','msg','order_id','out_biz_no','pay_date']|失败时['code','msg','sub_code','sub_msg']，成功时code=10000
     */
    public function fundTransToAccountTransfer($payeeAccount, $outBizNo, $amount, $remark = '深圳玩动科技转账') {
        $this->_init();
        $request = new \AlipayFundTransToaccountTransferRequest();
        $content = array(
            "out_biz_no" => $outBizNo,
            "payee_type" => "ALIPAY_USERID",
            "payee_account" => $payeeAccount,
            "amount" => $amount,
            "remark" => $remark
        );
        $request->setBizContent(json_encode($content));
        $result = $this->aop->execute($request);
        $responseNode = $this->_getResponseNode($request);
        return json_decode($result->$responseNode, true);
    }

    #endregion

    #region 查询转账订单接口 （alipay.fund.trans.order.query）

    /**
     * 查询转账订单接口（两单号选一，有$order_id时$out_biz_no失效）
     * @param $outBizNo 商户转账唯一订单号 即本平台唯一订单号
     * @param $orderId 支付宝转账单据号 即转账后支付宝返回的单号
     * @return array
     * 成功时['arrival_time_end','code','msg','order_fee','order_id','out_biz_no','pay_date','status']，status有SUCCESS、FAIL、INIT（等待处理）、DEALING（处理中），order_fee：转账金额
     * 失败时['code','msg','sub_code','sub_msg']
     */
    public function fundTransOrderQuery($outBizNo, $orderId = null) {
        $this->_init();
        $request = new AlipayFundTransOrderQueryRequest ();
        $content = array(
            "out_biz_no" => $outBizNo,
            "order_id" => $orderId
        );
        $request->setBizContent(json_encode($content));
        $result = $this->aop->execute($request);
        $responseNode = $this->_getResponseNode($request);
        return json_decode($result->$responseNode, true);
    }

    #endregion

    #endregion

    #region 芝麻认证相关

    #region 芝麻认证初始化（zhima.customer.certification.initialize）

    /**
     * 认证初始化
     * @param $transactionId 商户请求的唯一标志
     * @param $certName 身份证名称
     * @param $certNO 身份证号码
     * @return bool
     */
    public function zhimaCustomerCertificationInitialize($transactionId, $certName, $certNO) {
        // 初始化
        $this->_init();
        // 认证初始化
        $request = new \ZhimaCustomerCertificationInitializeRequest();
        $content = array(
            "transaction_id" => $transactionId,
            "product_code" => "w1010100000000002978",
            "biz_code" => "FACE",
            "identity_param" => json_encode(array(
                "identity_type" => "CERT_INFO",
                "cert_type" => "IDENTITY_CARD",
                "cert_name" => $certName,
                "cert_no" => $certNO,
            )),
        );
        $request->setBizContent(json_encode($content));

        $result = $this->aop->execute($request);
        $responseNode = $this->_getResponseNode($request);
        return $result->$responseNode;
    }

    #endregion

    #region  芝麻认证开始认证（zhima.customer.certification.certify）

    /**
     * 芝麻认证开始认证
     * @param $bizNo 一次认证的唯一标识
     * @return string
     */
    public function zhimaCustomerCertificationCertify($bizNo) {
        $this->_init();
        $request = new \ZhimaCustomerCertificationCertifyRequest ();
        $request->setBizContent(json_encode(array("biz_no" => $bizNo)));
        $request->setReturnUrl($this->config->returnUrl);

        $response = $this->aop->pageExecute($request, "GET");
        return $response;
    }

    #endregion

    #region 芝麻认证查询 （zhima.customer.certification.query）

    /**
     * 芝麻认证查询
     * @param $bizNo 一次认证的唯一标识
     * @return string
     */
    public function zhimaCustomerCertificationQuery($bizNo) {
        $this->_init();
        $request = new \ZhimaCustomerCertificationQueryRequest();
        $request->setBizContent(json_encode(array("biz_no" => $bizNo)));

        $result = $this->aop->execute($request);
        $responseNode = $this->_getResponseNode($request);
        return $result->$responseNode;
    }

    #endregion

    #endregion

    #region 换取授权访问令牌（alipay.system.oauth.token）

    /**
     * 换取授权访问令牌
     * @param $authCode 支付宝授权码
     * @return string
     */
    public function systemOauthToken($authCode) {
        $this->_init();
        $request = new \AlipaySystemOauthTokenRequest();
        $request->setGrantType("authorization_code");
        $request->setCode($authCode);
        $result = $this->aop->execute($request);

        $responseNode = $this->_getResponseNode($request);
        return $result->$responseNode;
    }

    #endregion

    #region 支付宝会员授权信息查询接口 （alipay.user.info.share）

    /**
     * 支付宝会员授权信息查询接口
     * @param $accessToken 支付宝用户授权信息
     * @return array
     */
    public function userInfoShare($accessToken) {
        $this->_init();
        $request = new \AlipayUserInfoShareRequest ();
        $result = $this->aop->execute($request, $accessToken);

        $responseNode = $this->_getResponseNode($request);
        return $result->$responseNode;
    }

    #endregion

    #region 获取支付宝登录授权请求参数

    /**
     * 获取支付宝登录授权请求参数
     * @param $targetId 商户请求的唯一标志
     * @return string
     */
    function getOAuthParams($targetId) {
        $this->_init();
        $signType = "RSA2";
        $data = array(
            "apiname" => "com.alipay.account.auth",
            "app_id" => $this->config->appId,
            "app_name" => "mc",
            "auth_type" => "AUTHACCOUNT",
            "biz_type" => "openservice",
            "method" => "alipay.open.auth.sdk.code.get",
            "pid" => $this->config->pId,
            "product_id" => "APP_FAST_LOGIN",
            "scope" => "kuaijie",
            "sign_type" => $signType,
            "target_id" => $targetId
        );
        $data["sign"] = urlencode($this->aop->rsaSign($data, $signType));
        return $this->aop->getSignContent($data);
    }

    #endregion

    #region 支付相关

    #region 获取App支付请求参数

    /**
     * 获取App支付请求参数
     * @param $body 对一笔交易的具体描述信息
     * @param $subject 商品的标题/交易标题/订单标题/订单关键字等
     * @param $outTradeNo 商户网站唯一订单号
     * @param $totalAmount 订单总金额，单位为元，精确到小数点后两位
     * @param string $timeoutExpress 该笔订单允许的最晚付款时间，逾期将关闭交易
     *      取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
     *      该参数数值不接受小数点， 如 1.5h，可转换为 90m。注：若为空，则默认为15d。
     * @param int $goodsType 商品主类型：0—虚拟类商品，1—实物类商品
     * @return string
     */
    function getAppPayParams($body, $subject, $outTradeNo, $totalAmount,$timeoutExpress, $goodsType = 0) {
        $this->_init();
        // $this->config->notifyUrl
        $signType = "RSA2";
        $data = array(
            "app_id" => $this->config->appId,
            "method" => "alipay.trade.app.pay",
            "charset" => "utf-8",
            "sign_type" => $signType,
            "timestamp" => date("Y-m-d h:i:s"),
            "version" => "1.0",
            "notify_url" => $this->config->notifyUrl
        );
        // 业务请求参数的集合
        $content = array(
            "body" => $body,
            "subject" => $subject,
            "out_trade_no" => $outTradeNo,
            "total_amount" => $totalAmount,
            "product_code" => "QUICK_MSECURITY_PAY",
            "timeout_express" => $timeoutExpress,
            "goods_type" => $goodsType
        );
        $data["biz_content"] = json_encode($content);
        $data["sign"] = $this->aop->rsaSign($data, $signType);
        return $this->aop->getSignContentUrlencode($data);
    }

    #endregion

    #region 支付通知

    /**
     * 交易创建，等待买家付款，不触发通知
     */
    const WAIT_BUYER_PAY = "WAIT_BUYER_PAY";

    /**
     * 未付款交易超时关闭，或支付完成后全额退款，触发通知
     */
    const TRADE_CLOSED = "TRADE_CLOSED";

    /**
     * 交易支付成功，触发通知
     */
    const TRADE_SUCCESS = "TRADE_SUCCESS";

    /**
     * 交易结束，不可退款，触发通知
     */
    const  TRADE_FINISHED = "TRADE_FINISHED";

    /**
     * 支付通知
     * @param $params 支付通知参数
     * @return array
     */
    function notify($params) {
        $this->_init();
        if ($this->aop->rsaCheckV1($params, "", "RSA2") && $params["app_id"] == $this->aop->appId) {
            return array(
                "trade_no" => $params["trade_no"], // 支付宝交易号
                "out_trade_no" => $params["out_trade_no"], // 商户订单号
                "trade_status" => $params["trade_status"], // 交易状态
                "total_amount" => $params["total_amount"], // 订单金额
                "gmt_payment" => $params["gmt_payment"] // 该笔交易的买家付款时间
            );
        }
        return false;
    }

    #endregion

    #endregion

    #region 获取Response Node

    /**
     * 获取Response Node
     * @param $request 请求对象
     * @return string
     */
    private function _getResponseNode($request) {
        return str_replace(".", "_", $request->getApiMethodName()) . "_response";
    }

    #endregion

}